# coding=utf-8
"""
author = jamon
"""

import hashlib
from typing import Optional, Dict, List, Callable, Any

from websockets import WebSocketServerProtocol

# from obespoir.base.common_define import NodeType
from obespoir.config import TransportInfo, Config, RouteRule, NodeTypeName
from obespoir.share.singleton import Singleton


class GlobalObject(object, metaclass=Singleton):
    """
    全局对象
    """

    def __init__(self):
        self.name: str = None
        self.id: str = None
        self.type: str = None

        self.http_server = None           # httpserver server

        self.rpc_server = None            # rpcserver server
        self.rpc_password: str = "helloworldiloveyou~1234567890123"
        self.rpc_encode_type = 0          # rpc加密类型
        self.rpc_route: Optional[RouteRule] = None  # 接收到rpc消息后的配置路由
        self.rpc_reconnect_time: int  = 5     # rpc重连时间

        self.ws_server = None             # websocketserver server
        self.ws_password = "helloworldiloveyou~1234567890123"
        self.ws_encode_type = 0           # websocket加密类型
        self.ws_timeout = 300
        self.ws_no_state_msg = {}        # 无状态的消息配置

        self.loop = None
        self.remote_ports: Dict[NodeTypeName, List[TransportInfo]] = {}

        self.after_open_handler: Callable[[WebSocketServerProtocol], Any] = None  # noqa
        self.after_close_handler: Callable[[WebSocketServerProtocol], Any] = None  # noqa

        self.default_frame_config = None

    def init_from_config(self, config: Config):
        """

        :param config: Config
        :return:
        """
        self.name = config.name
        self.type = config.type

        self.rpc_password = config.rpc.token
        self.rpc_encode_type = config.rpc.encode
        self.rpc_route = config.rpc_route_rule
        self.id = self.gen_id(config.host, config.rpc.port)

        if config.websocket:
            self.ws_password = config.websocket.token
            self.ws_encode_type = config.websocket.encode
            # self.ws_no_state_msg = config.websocket.no_state
            # if not self.validate_no_state():
            #     raise Exception("ws_no_state_msg config error！")

    def is_proxy(self):
        return self.type == NodeTypeName.PROXY.value

    @staticmethod
    def gen_id(host: str, port: int) -> str:
        c_md5 = hashlib.md5()
        c_md5.update("{}_{}".format(host, port).encode("utf-8"))
        return c_md5.hexdigest()[:16]

    def update_remote_ports(self, remote_ports: List[TransportInfo]):
        """

        :param remote_ports: [{}, ...]
        :return:
        """
        for info in remote_ports:
            t = info.type
            if t not in self.remote_ports:
                self.remote_ports[t] = [info]
            else:
                self.remote_ports[t].append(info)

    def validate_no_state(self):
        """
        验证路由配置是否正确
        :return: 0/1
        """
        for info in self.ws_no_state_msg.get("range", []):
            if not isinstance(info, list):
                return 0

            if 2 != len(info) or info[0] > info[1] or not isinstance(
                info[0], int) or not isinstance(info[1], int):
                return 0

        for info in self.ws_no_state_msg.get("special", []):
            for s in info:
                if not isinstance(s, int):
                    return 0

        return 1
